/**
 * 
 */
package cream.alarm.db;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import cream.alarm.model.Weekday;
import cream.alarm.util.DateUtil;
import cream.alarm.util.StringUtil;

/**
 * 数据库操作类
 * 
 * @author Cream
 * 
 */
public class DbAdapter {

	public static final String KEY_DATE = "date";
	public static final String KEY_IS_WEEKDAY = "isWeekday";
	public static final String KEY_TYPE = "type";
	public static final String KEY_DESC = "desc";

	private static final String TAG = "DbAdapter";
	private DatabaseHelper mDbHelper;
	private SQLiteDatabase mDb;

	private static final String DB_NAME = "weekdayAlarm";
	private static final String DB_TABLE = "weekdays";
	private static int DB_VERSION = 1;

	private final Context mCtx;

	private static class DatabaseHelper extends SQLiteOpenHelper {

		public DatabaseHelper(Context context) {
			super(context, DB_NAME, null, DB_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			StringBuilder sql = new StringBuilder();
			sql.append("CREATE TABLE ");
			sql.append(DB_TABLE);
			sql.append("(");
			sql.append(KEY_DATE);
			sql.append(" TEXT PRIMARY KEY, ");
			sql.append(KEY_IS_WEEKDAY);
			sql.append(" TEXT NOT NULL, ");
			sql.append(KEY_TYPE);
			sql.append(" TEXT, ");
			sql.append(KEY_DESC);
			sql.append(" TEXT);");

			Log.d(TAG, "Creating Database, Sql:" + sql.toString());

			db.execSQL(sql.toString());
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.d(TAG, "Upgrading database from version " + oldVersion + " to "
					+ newVersion + ", now will do nothing! ^_^");
			// TODO when database need to be upgraded.
		}
	}

	public DbAdapter(Context ctx) {
		this.mCtx = ctx;
	}

	public DbAdapter open() {
		mDbHelper = new DatabaseHelper(mCtx);
		mDb = mDbHelper.getWritableDatabase();
		return this;
	}

	public void close() {
		if (mDbHelper != null) {
			mDbHelper.close();
		}
	}

	/**
	 * 创建工作日
	 * 
	 * @param weekday
	 * @return
	 */
	public long createWeekday(Weekday weekday) {
		if (weekday == null) {
			throw new IllegalArgumentException("weekday is missing!");
		}

		ContentValues cv = new ContentValues();

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

		cv.put(KEY_DATE, sdf.format(weekday.getDate().getTime()));
		cv.put(KEY_IS_WEEKDAY, weekday.isWeekday());
		cv.put(KEY_TYPE, weekday.getType());
		cv.put(KEY_DESC, weekday.getDesc());

		return mDb.insert(DB_TABLE, null, cv);
	}

	/**
	 * 删除指定日期的“工作日”信息
	 * 
	 * @param date
	 * @return
	 */
	public boolean deleteWeekday(String date) {
		if (StringUtil.isEmpty(date)) {
			throw new IllegalArgumentException("date is missing");
		}
		return mDb.delete(DB_TABLE, KEY_DATE + "=" + date, null) > 0;
	}

	/**
	 * 更新“工作日”信息
	 * 
	 * @param weekday
	 * @return
	 */
	public boolean updateWeekday(Weekday weekday) {
		if (weekday == null) {
			throw new IllegalArgumentException("weekday is missing");
		}
		ContentValues cv = new ContentValues();

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

		cv.put(KEY_DATE, sdf.format(weekday.getDate().getTime()));
		cv.put(KEY_IS_WEEKDAY, weekday.isWeekday());
		cv.put(KEY_TYPE, weekday.getType());
		cv.put(KEY_DESC, weekday.getDesc());

		return mDb.update(DB_TABLE, cv, KEY_DATE + "=" + weekday.getDate(),
				null) > 0;
	}

	/**
	 * 查询指定日期是否为“工作日”。
	 * 
	 * @param date
	 * @return
	 * @throws IllegalArgumentException
	 *             参数不存在时
	 */
	public boolean isWeekday(Date date) {
		if (date == null) {
			throw new IllegalArgumentException("argument 'date' is null!");
		}

		Weekday weekday = this.fetchWeekday(date);
		return weekday.isWeekday();
	}

	/**
	 * 查询指定日期是否为“工作日”。
	 * 
	 * @param dateStr
	 * @return
	 * @throws ParseException
	 *             入参格式不为 "yyyy-MM-dd" 时抛出
	 */
	public boolean isWeekday(String dateStr) throws ParseException {
		Date date = DateUtil.parse(dateStr);

		return this.isWeekday(date);
	}

	/**
	 * 通过指定日期获取“工作日”信息
	 * 
	 * @param date
	 * @return
	 */
	public Weekday fetchWeekday(Date date) {
		if (date == null) {
			throw new IllegalArgumentException("argument 'date' is NULL");
		}

		Cursor cursor = mDb.query(DB_TABLE, new String[] { KEY_DATE,
				KEY_IS_WEEKDAY, KEY_TYPE, KEY_DESC }, null, null, null, null,
				null);
		String dateStr = cursor.getString(0);
		String isWeekday = cursor.getString(1);
		String type = cursor.getString(2);
		String desc = cursor.getString(3);

		Weekday weekday = null;
		try {
			weekday = new Weekday(dateStr, isWeekday, type, desc);
		} catch (ParseException e) {
			Log.e(TAG, "Data format error!!", e);
		}
		return weekday;
	}

	/**
	 * 通过指定日期获取“工作日”信息
	 * 
	 * @param dateStr
	 * @return
	 * @throws ParseException
	 *             入参格式不为 "yyyy-MM-dd" 时抛出
	 */
	public Weekday fetchWeekday(String dateStr) throws ParseException {
		Date date = DateUtil.parse(dateStr);

		return this.fetchWeekday(date);
	}

	/**
	 * 通过指定时间段返回数据库光标。<br />
	 * 返回元素顺序为 KEY_DATE, KEY_IS_WEEKDAY, KEY_TYPE, KEY_DESC
	 * 
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public Cursor fetchWeekdays(Date startDate, Date endDate) {

		String startDateStr = DateUtil.format(startDate);
		String endDateStr = DateUtil.format(endDate);

		return mDb
				.query(DB_TABLE, new String[] { KEY_DATE, KEY_IS_WEEKDAY,
						KEY_TYPE, KEY_DESC }, KEY_DATE + ">=? AND " + KEY_DATE
						+ "<=?", new String[] { startDateStr, endDateStr },
						null, null, KEY_DATE);
	}

	/**
	 * 通过指定时间段返回数据库光标
	 * 
	 * @param startDateStr
	 * @param endDateStr
	 * @return
	 * @throws ParseException
	 *             入参格式不为 "yyyy-MM-dd" 时抛出
	 */
	public Cursor fetchWeekdays(String startDateStr, String endDateStr)
			throws ParseException {
		// 此方法存在是为了方便外部调用。
		// 在 fetchWeekdays(Date, Date) 的实现中，又将 Date 类型转为 String 是因为数据库接口的需求。
		// 而此方法通过调用上述方法实现，主要考虑是通过一次转换确保数据格式的正确性，尽早的发现程序中可能存在的bug

		Date startDate = DateUtil.parse(startDateStr);
		Date endDate = DateUtil.parse(endDateStr);

		return this.fetchWeekdays(startDate, endDate);
	}

	/**
	 * 通过指定时间段返回数据列表
	 * 
	 * @param start
	 * @param end
	 * @return
	 */
	public List<Weekday> fetchWeekdayList(Date start, Date end) {
		Cursor cursor = fetchWeekdays(start, end);

		List<Weekday> resultList = new LinkedList<Weekday>();

		if (cursor.moveToFirst()) {
			while (cursor.moveToNext()) {
				String dateStr = cursor.getString(0);
				String isWeekday = cursor.getString(1);
				String type = cursor.getString(2);
				String desc = cursor.getString(3);

				Weekday weekday = null;
				try {
					weekday = new Weekday(dateStr, isWeekday, type, desc);
				} catch (ParseException e) {
					Log.e(TAG, "Data format error!!", e);
				}
				resultList.add(weekday);
			}
		}
		return resultList;
	}

	public Map<Date/* date */, Weekday> fetchWeekdayMap(Date start, Date end) {
		Cursor cursor = fetchWeekdays(start, end);

		Map<Date, Weekday> resultList = new HashMap<Date, Weekday>();

		if (cursor.moveToFirst()) {
			while (cursor.moveToNext()) {
				String dateStr = cursor.getString(0);
				String isWeekday = cursor.getString(1);
				String type = cursor.getString(2);
				String desc = cursor.getString(3);

				Weekday weekday = null;
				Date d = null;
				try {
					weekday = new Weekday(dateStr, isWeekday, type, desc);
					d = DateUtil.parse(dateStr);
				} catch (ParseException e) {
					Log.e(TAG, "Data format error!!", e);
					throw new RuntimeException(e);
				}
				resultList.put(d, weekday);
			}
		}
		return resultList;
	}
}
